This section displays how much of each land use type is covered by trees. For example, a value of 60 for ‘Streets’ means that 60% of total street area is under canopy coverage. Accordingly, if ‘Parks’ is a low number, it means parks are not shaded, not that there are few parks in a region, it is just likely they are open spaces.
Code
street_trees_grouped <-coverage(exp =expression(zone_short =='roads'), type ='street', group = grouping)reserve_trees_grouped <-coverage(exp =expression(feature_type =='reserve'), type ='reserve', group = grouping) resi_trees_grouped <-coverage(exp =expression(zoning_permits_housing =='Housing permitted'), type ='residential', group = grouping) #combine into one and cleancombined_df <- street_trees_grouped %>%left_join(reserve_trees_grouped, by = grouping) %>%left_join(resi_trees_grouped, by = grouping) %>% dplyr::select(c(grouping,'street_percentage', 'reserve_percentage', 'residential_percentage')) %>%left_join(grouping_sf %>%st_drop_geometry() %>%select(grouping, distance), by = grouping) %>%rowwise() %>%# mutate(distance = distance_map[as.character(as.name(grouping))]) %>%mutate(distance = distance /1000) %>%mutate(across(where(is.numeric), ~round(.x, 1))) %>%mutate(across(ends_with('percentage'), ~ifelse(is.na(.x), 0, .x) )) %>%ungroup() %>%as.data.frame()sd_combined = SharedData$new((combined_df))
Note: the table below is sorted by street tree coverage by default. Click other column names to sort them.
Note: There might be innaccuracies in the street coverage data when using Suburbs as grouping unit, as not all Statistical Area 1s fit uniquely within a suburb. As such, SA1s are assigned into suburbs based on the one they have the highest overlap with.
Code
filter_slider("distance", "Distance to CBD", sd_combined, ~distance, min =0, max =max(sd_combined$data()$distance), width ='75%')
YM recently released Housing Targets, a data-driven model which allocates housing targets by council.
This page calculates how much tree cover might be lost in the upzoning of residential lots, and then calculating how to offset this loss by increasing coverage of street trees
This section breaks down canopy coverage by zone type. As expected, low density residential and civic land (parks) top the list. It is tempting to note that Greenfield is below industrial, however, Greenfield by definition has not had enough time for planted trees to grow large enough for canopy cover.
This section shows the interaction between public tree coverage and the cost of living in an area, depicted by both house prices and median rents. Public tree coverage is defined as:
\[
\text{Public tree coverage} = \frac{\text{area of streets covered by trees + area of parks covered by trees}}{\text{area of streets + area of parks}}
\]
Data Note: Rents are using ABS data, which is only available in ranges. Therefore, median rents are defined as whatever bin the median observation falls into. Also note that the Census was in 2021, and therefore rents may be impacted by COVID, and may have changed since. House prices are from Housing Victoria, and are an average of the last 5 quarters median prices.
TODO: Check Public Definitions
Code
lot_sizes <- agg_df %>%filter(zoning_permits_housing =='Housing permitted') %>%group_by(SAL_NAME21) %>%summarise(med_lot =median(lot_size, na.rm =TRUE), n =n()) %>%rowwise()rents =read_csv('../data/rents_by_sal.csv') %>%manipulateRents() %>%rowwise() %>%mutate(median_band =gsub('\\$', '', median_band)) public_coverage <-coverage(exp =expression(feature_preventing_development ==TRUE| zone_short =='roads'), type ='public', group = grouping) %>%select('SAL_NAME21', 'public_percentage')house_price_data = readxl::read_xls('../data/Median-House-Price-3rd-Quarter.xls', skip =1)[-c(1:5),1:6] house_price_data = house_price_data %>%rowwise() %>%mutate(avg =mean(as.numeric(c(`Jul - Sep 2022...2`,`Oct - Dec 2022`,`Jan - Mar 2023`,`Apr - Jun 2023...5`,`Jul - Sep 2023...6`)), na.rm =TRUE)) %>%select(SUBURB, avg,) %>%rename(SAL_NAME21 = SUBURB) %>%mutate(SAL_NAME21 =str_to_title(SAL_NAME21)) %>%left_join(combined_df, by = grouping) %>%filter(!is.na(distance), !is.na(avg)) %>%rename(average_house_price = avg) %>%mutate(average_house_price = average_house_price /10^6) %>%left_join(lot_sizes, by ='SAL_NAME21') %>%left_join(rents, by ='SAL_NAME21') %>%left_join(public_coverage, by ='SAL_NAME21') %>%adf() %>%mutate(median_band =as.factor(median_band)) %>%mutate(within15 =ifelse(distance <15, T, F))#house_price_data = house_price_data %>% left_join(directions, by = 'SAL_NAME21')#missing_suburbs = setdiff(combined_df$SAL_NAME21, house_price_data$SAL_NAME21)#wtfhouse_interactable = SharedData$new(house_price_data)filter_slider("distance", "Distance to CBD", house_interactable, max =30, ~distance, width ='75%')
Code
# price_street_plot <- ggplot(house_interactable, mapping = aes(x = average_house_price, y = street_percentage, text = SAL_NAME21), axe) + xlab('Average House Price ($m)') + ylab('Street Tree Coverage (%)') + geom_point(color = "#006D2C") + theme_minimal()# # price_residential_plot <- ggplot(house_interactable, mapping = aes(x = average_house_price, y = residential_percentage, text = SAL_NAME21), axe) + xlab('Average House Price ($m)') + ylab('Residential Area Tree Coverage (%)') + geom_point(color = "#006D2C") + theme_minimal()price_public_plot <-ggplot(house_interactable, mapping =aes(x = average_house_price, y = public_percentage, text = SAL_NAME21, fill = within15, stroke =NA), axe) +xlab('Average House Price ($m)') +ylab(' Tree Coverage of Public Areas (%)') +geom_point() +labs(caption ="Source: Housing Victoria") +theme_minimal()rents_public_plot <- (ggplot(house_interactable, mapping =aes(x = median_band, y = public_percentage, text = SAL_NAME21)) +geom_boxplot(color ="#006D2C") +xlab('Median Rent (2021 dollars)') +ylab("Tree Coverage of Public Areas (%)") +theme_minimal() +labs(caption ="Source: 2021 Census (ABS)") +theme(axis.text.x =element_text(angle =45)) ) #bscols(widths = c(4,4), ggplotly(price_street_plot), ggplotly(price_residential_plot))#subplot(ggplotly(price_street_plot),ggplotly(price_residential_plot), titleY = T, titleX = T)ggplotly(price_public_plot)
The above figure displays the relationship between house prices and public tree coverage. There is a tangible correlation between the two variables as suburbs with higher house prices tend to have more public tree coverage. This is not a statement of causation, merely correlation.
The data is further split into two groups: suburbs within 15 kilometres of the city, and suburbs outside the 15km range. This split reveals two distinct spatial patterns.
For ‘inner’ suburbs, the relationship is much steeper. For outer suburbs, the slope of a best fit line is much shallower.